﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using System.Windows.Forms;

namespace RotatoLoader2010
{
  public partial class Form1 : Form
  {
		#region Fields (1) 

    static Dictionary<WebClient, ListViewItem> wc2url = new Dictionary<WebClient, ListViewItem>();

		#endregion Fields 

		#region Constructors (1) 

    public Form1()
    {
      InitializeComponent();
    }

		#endregion Constructors 

		#region Methods (13) 

		// Private Methods (13) 

    private void btnMapFolderChooser_Click(object sender, EventArgs e)
    {
      fldrMapChooser.SelectedPath = loadMapPathFromRegistry();
      if (fldrMapChooser.ShowDialog() == DialogResult.OK)
      {
        txtMapPath.Text = fldrMapChooser.SelectedPath;
      }
    }

    private void btnReadMapPathFromRegistry_Click(object sender, EventArgs e)
    {
      txtMapPath.Text = loadMapPathFromRegistry();
    }

    private void btnSync_Click(object sender, EventArgs e)
    {
      listView1.Items.Clear();
      processRemoteFiles();

    }

    private static void decompressFile(string src, string dest)
    {
      try
      {
        ICSharpCode.SharpZipLib.BZip2.BZip2.Decompress(File.OpenRead(src), File.Create(dest));
        File.Delete(src);
      }
      catch { }
    }

    void fileDownloader_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
    {
      ListViewItem i = wc2url[(WebClient)sender];
      string strStatus = "Decompressing...";

      i.SubItems[1].Text = strStatus;
      string src = i.SubItems[2].Text;
      string dest = src.Replace(".bz2", "");
      BackgroundWorker worker = new BackgroundWorker();

      worker.DoWork += worker_DoWork;
      worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
      worker.RunWorkerAsync(new object[] { src, dest,sender });

    }

    void fileDownloader_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
      ListViewItem i = wc2url[(WebClient)sender];
      string strStatus = string.Format("{0}% ({1}K)", e.ProgressPercentage.ToString(), e.BytesReceived / 1024);
      i.SubItems[1].Text = strStatus;
    }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
      Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
      config.AppSettings.Settings["serverName"].Value = txtMapServer.Text;
      config.AppSettings.Settings["mapPath"].Value = txtMapPath.Text;
      config.Save();
      e.Cancel = false;
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      initStrings();
      if (string.Empty == txtMapPath.Text)
      {
        txtMapPath.Text = loadMapPathFromRegistry();
      }
      if (string.Empty == txtMapPath.Text)
      {

      }

    }

    private void initStrings()
    {
      Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
      txtMapServer.Text = config.AppSettings.Settings["serverName"].Value;
      txtMapPath.Text = config.AppSettings.Settings["mapPath"].Value;
      regModPathKey = config.AppSettings.Settings["registrySubKey"].Value;
      regModPathValue = config.AppSettings.Settings["registryValue"].Value;
    }

    /// <summary>
    /// Attempts to read the user's map path from the registry.
    /// </summary>
    /// <returns>A default of the existing map path (which may be empty) or the results of the modpath.</returns>
    private string loadMapPathFromRegistry()
    {
      string retVal = txtMapPath.Text;
      try
      {
        retVal = (string)Microsoft.Win32.Registry.CurrentUser.OpenSubKey(regModPathKey).GetValue(regModPathValue);
      }
      catch (Exception e)
      {
        MessageBox.Show(e.Message, "There was an error reading from the registry, use the file picker.", MessageBoxButtons.OK);
      }
      return retVal;
    }

    private void processRemoteFiles()
    {
      // oh my god a regex to parse html
      string anchorPattern = "<a.*href=[\"'](?<url>[^\"]+[.\\s]*)[\"'].*>(?<name>[^<]+[.\\s]*)</a>";
      RegexOptions rOpts = RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled;
      MatchCollection matches;
      using (WebClient wc = new WebClient())
      {
         matches = Regex.Matches(wc.DownloadString(new Uri(txtMapServer.Text)), anchorPattern, rOpts);
      }
       
      if (matches.Count > 0)
      {
        
        foreach (Match m in matches)
        {
          if (!m.Groups["url"].Value.EndsWith(".bz2")) continue;

          string url = m.Groups["url"].Value;
          string destPackedFile = txtMapPath.Text + "\\" + url;
          string destUnpacked = destPackedFile.Replace(".bz2", "");
          // possibly a remnant from a previous download attempt?
          // TODO: resume downloading?
          if (File.Exists(destPackedFile)) File.Delete(destPackedFile);

          if (!File.Exists(destUnpacked))
          {
            ListViewItem lvItem = new ListViewItem(
              new string[] {txtMapServer.Text + url, "Pending",destPackedFile}
            );
            listView1.Items.Add(lvItem);
            using (WebClient fileDownloader = new WebClient())
            {
              wc2url.Add(fileDownloader, lvItem);
              fileDownloader.DownloadProgressChanged += new DownloadProgressChangedEventHandler(fileDownloader_DownloadProgressChanged);
              fileDownloader.DownloadFileCompleted += new AsyncCompletedEventHandler(fileDownloader_DownloadFileCompleted);
              fileDownloader.DownloadFileAsync(new Uri(txtMapServer.Text + url), destPackedFile,fileDownloader );
            }
          }

        }
        this.toolStripStatusLabel1.Text = "Maps to download: " + listView1.Items.Count;
      }
    }

    void worker_DoWork(object sender, DoWorkEventArgs e)
    {
      object[] oS = (object[])e.Argument;
      string src = (string)oS[0];      
      string dest = (string)oS[1];
      WebClient parent = (WebClient)oS[2];
      decompressFile(src, dest);
      e.Result = e.Argument;
    }

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
      object[] oS = (object[])e.Result;
      ListViewItem i = wc2url[(WebClient)oS[2]];
      i.SubItems[1].Text = "Completed.";
    }

		#endregion Methods 

    static string regModPathKey, regModPathValue;
  }
}
